package hu.mapro.gwtui.client.browser;

import hu.mapro.gwtui.client.MessageInterface;
import hu.mapro.gwtui.client.data.SortField;
import hu.mapro.gwtui.client.data.SortFieldProxy;
import hu.mapro.gwtui.client.data.SortUtils;

import java.util.Collections;
import java.util.List;

import com.google.common.collect.Lists;
import com.google.gwt.core.client.Callback;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

/**
 * An abstract request factory proxy that supports processing results using
 * either a RPC style <code>Callback</code> or a <code>RequestFactory</code>
 * <code>Receiver</code>.
 * 
 * @param <C>
 *            the type of data used to configure the load from the proxy
 * @param <D>
 *            the type of data being returned by the data proxy
 */
public abstract class RFLoader<T, R extends RequestContext> implements Loader<T> {
	
	MessageInterface ui;
	
	public RFLoader(MessageInterface ui) {
		super();
		this.ui = ui;
	}

	abstract public R createRequestContext();

	abstract public Request<Long> createCountRequest(R requestContext);

	abstract public Request<List<T>> createListRequest(R requestContext,
			int firstResult, int maxResults, List<SortFieldProxy> sortConfig);
	
	public void load(int firstResult, int maxResults, List<SortField> sortConfig, final Callback<LoadResult<T>, Throwable> callback) {

		final List<ServerFailure> errors = Lists.newArrayList();
		
		final LoadResult<T> plr = new LoadResult<T>();
		
		R requestContext = createRequestContext();
		Request<Long> countRequest = createCountRequest(requestContext);
		if (countRequest!=null) {
			countRequest.to(new Receiver<Long>() {
				@Override
				public void onFailure(ServerFailure error) {
					errors.add(error);
				}
				@Override
				public void onSuccess(Long response) {
					plr.setCount(response.longValue());
				}
			});
		}
		createListRequest(requestContext, firstResult, maxResults, SortUtils.createSortFields(sortConfig,requestContext)).to(new Receiver<List<T>>() {
			@Override
			public void onFailure(ServerFailure error) {
				errors.add(error);
			}
			@Override
			public void onSuccess(List<T> response) {
				plr.setRecords(response);
			}
		});
		
		requestContext.fire(new Receiver<Void>() {
			@Override
			public void onFailure(ServerFailure error) {
				handleErrorsFatal(Collections.singletonList(error));
			}
			@Override
			public void onSuccess(Void response) {
				if (!handleErrorsFatal(errors)) {
					callback.onSuccess(plr);
				}
			}
		});
		
	}

	protected boolean handleErrorsFatal(List<ServerFailure> errors) {
		if (errors.isEmpty()) {
			return false;
		}
		
		boolean accessDenied = false;
		
		for (ServerFailure error : errors) {
			if ("hu.mapro.gwtui.client.login.AccessDeniedException".equals(error.getExceptionType())) {
				if (!accessDenied) {
					accessDenied = true;
					ui.alert("Access denied", "Your session might have expired. Try reloading the page.", null);
				}
			} else {
				ui.alert("Error contacting the server", error.getMessage(), null);
			}
		}
		
		return true;
	}
	
	
	
}
